use crate::rtmp::chunk::packetizer::ChunkPacketizer;
use crate::rtmp::chunk::ChunkInfo;
use crate::rtmp::net_stream::errors::NetStreamError;
use crate::rtmp::{chunk, messages};
use bytesio::bytesio::TNetIO;
use indexmap::IndexMap;
use std::sync::Arc;
use tokio::sync::Mutex;
use xflv::amf0::amf0_writer::Amf0Writer;
use xflv::amf0::Amf0ValueType;

// 网络流写入器结构体
pub struct NetStreamWriter {
    // AMF0写入器，用于将数据编码为AMF0格式
    amf0_writer: Amf0Writer,
    // 块打包器，用于将数据打包成RTMP块
    packetizer: ChunkPacketizer,
}

impl NetStreamWriter {
    pub fn new(io: Arc<Mutex<Box<dyn TNetIO + Send + Sync>>>) -> Self {
        Self {
            amf0_writer: Amf0Writer::new(),       // 初始化AMF0写入器
            packetizer: ChunkPacketizer::new(io), // 初始化块打包器
        }
    }

    // 写入块
    async fn write_chunk(&mut self, msg_stream_id: u32) -> Result<(), NetStreamError> {
        // 获取当前写入的字节数据
        let data = self.amf0_writer.extract_current_bytes();

        // 创建块信息
        let mut chunk_info = ChunkInfo::new(
            chunk::define::csid_type::COMMAND_AMF0_AMF3,
            chunk::define::chunk_type::TYPE_0,
            0,
            data.len() as u32,
            messages::define::msg_type_id::COMMAND_AMF0,
            msg_stream_id,
            data,
        );

        self.packetizer.write_chunk(&mut chunk_info).await?;
        Ok(())
    }

    // 写入播放命令
    pub async fn write_play(
        &mut self,
        transaction_id: &f64,
        stream_name: &String,
        start: &f64,
        duration: &f64,
        reset: &bool,
    ) -> Result<(), NetStreamError> {
        // 写入命令名称
        self.amf0_writer.write_string(&String::from("play"))?;
        // 写入事务ID
        self.amf0_writer.write_number(transaction_id)?;
        // 写入空值
        self.amf0_writer.write_null()?;
        // 写入流名称
        self.amf0_writer.write_string(stream_name)?;
        // 写入开始时间
        self.amf0_writer.write_number(start)?;
        // 写入持续时间
        self.amf0_writer.write_number(duration)?;
        // 写入重置标志
        self.amf0_writer.write_bool(reset)?;

        self.write_chunk(0).await
    }

    // 写入删除流命令
    pub async fn write_delete_stream(
        &mut self,
        transaction_id: &f64,
        stream_id: &f64,
    ) -> Result<(), NetStreamError> {
        // 写入命令名称
        self.amf0_writer
            .write_string(&String::from("deleteStream"))?;
        // 写入事务ID
        self.amf0_writer.write_number(transaction_id)?;
        // 写入空值
        self.amf0_writer.write_null()?;
        // 写入流ID
        self.amf0_writer.write_number(stream_id)?;

        self.write_chunk(0).await
    }

    // 关闭流命令
    pub async fn write_close_stream(
        &mut self,
        transaction_id: &f64, // 事务ID
        stream_id: &f64,      // 流ID
    ) -> Result<(), NetStreamError> {
        // 写入命令名称
        self.amf0_writer
            .write_string(&String::from("closeStream"))?;
        // 写入事务ID
        self.amf0_writer.write_number(transaction_id)?;
        // 写入空值
        self.amf0_writer.write_null()?;
        // 写入流ID
        self.amf0_writer.write_number(stream_id)?;

        self.write_chunk(0).await
    }

    // 写入释放流命令
    pub async fn write_release_stream(
        &mut self,
        transaction_id: &f64,
        stream_name: &String,
    ) -> Result<(), NetStreamError> {
        // 写入命令名称
        self.amf0_writer
            .write_string(&String::from("releaseStream"))?;
        // 写入事务ID
        self.amf0_writer.write_number(transaction_id)?;
        // 写入空值
        self.amf0_writer.write_null()?;
        // 写入流名称
        self.amf0_writer.write_string(stream_name)?;

        self.write_chunk(0).await
    }

    // 写入FCPublish命令
    pub async fn write_fcpublish(
        &mut self,
        transaction_id: &f64,
        stream_name: &String,
    ) -> Result<(), NetStreamError> {
        // 写入命令名称
        self.amf0_writer.write_string(&String::from("FCPublish"))?;
        // 写入事务ID
        self.amf0_writer.write_number(transaction_id)?;
        // 写入空值
        self.amf0_writer.write_null()?;
        // 写入流名称
        self.amf0_writer.write_string(stream_name)?;

        self.write_chunk(0).await
    }

    // 写入接收音频命令
    async fn write_receive_audio(
        &mut self,
        transaction_id: &f64,
        enable: &bool,
    ) -> Result<(), NetStreamError> {
        // 写入命令名称
        self.amf0_writer
            .write_string(&String::from("receiveAudio"))?;
        // 写入事务ID
        self.amf0_writer.write_number(transaction_id)?;
        // 写入空值
        self.amf0_writer.write_null()?;
        // 写入启用标志
        self.amf0_writer.write_bool(enable)?;

        self.write_chunk(0).await
    }

    // 写入接收视频命令
    async fn write_receive_video(
        &mut self,
        transaction_id: &f64,
        enable: &bool,
    ) -> Result<(), NetStreamError> {
        // 写入命令名称
        self.amf0_writer
            .write_string(&String::from("receiveVideo"))?;
        // 写入事务ID
        self.amf0_writer.write_number(transaction_id)?;
        // 写入空值
        self.amf0_writer.write_null()?;
        // 写入启用标志
        self.amf0_writer.write_bool(enable)?;

        self.write_chunk(0).await
    }

    // 写入发布命令
    pub async fn write_publish(
        &mut self,
        transaction_id: &f64,
        stream_name: &String,
        stream_type: &String,
    ) -> Result<(), NetStreamError> {
        // 写入命令名称
        self.amf0_writer.write_string(&String::from("publish"))?;
        // 写入事务ID
        self.amf0_writer.write_number(transaction_id)?;
        // 写入空值
        self.amf0_writer.write_null()?;
        // 写入流名称
        self.amf0_writer.write_string(stream_name)?;
        // 写入流类型
        self.amf0_writer.write_string(stream_type)?;

        self.write_chunk(0).await
    }

    // 写入跳转命令
    async fn write_seek(&mut self, transaction_id: &f64, ms: &f64) -> Result<(), NetStreamError> {
        // 写入命令名称
        self.amf0_writer.write_string(&String::from("seek"))?;
        // 写入事务ID
        self.amf0_writer.write_number(transaction_id)?;
        // 写入空值
        self.amf0_writer.write_null()?;
        // 写入跳转时间
        self.amf0_writer.write_number(ms)?;

        self.write_chunk(0).await
    }

    // 写入暂停命令
    async fn write_pause(
        &mut self,
        transaction_id: &f64,
        pause: &bool,
        ms: &f64,
    ) -> Result<(), NetStreamError> {
        // 写入命令名称
        self.amf0_writer.write_string(&String::from("pause"))?;
        // 写入事务ID
        self.amf0_writer.write_number(transaction_id)?;
        // 写入空值
        self.amf0_writer.write_null()?;
        // 写入暂停标志
        self.amf0_writer.write_bool(pause)?;
        // 写入暂停时间
        self.amf0_writer.write_number(ms)?;

        self.write_chunk(0).await
    }

    // 写入带宽完成命令
    async fn write_on_bw_done(
        &mut self,
        transaction_id: &f64,
        bandwidth: &f64,
    ) -> Result<(), NetStreamError> {
        // 写入命令名称
        self.amf0_writer.write_string(&String::from("onBWDone"))?;
        // 写入事务ID
        self.amf0_writer.write_number(transaction_id)?;
        // 写入空值
        self.amf0_writer.write_null()?;
        // 写入带宽
        self.amf0_writer.write_number(bandwidth)?;

        self.write_chunk(0).await
    }

    // 写入状态命令
    pub async fn write_on_status(
        &mut self,
        transaction_id: &f64,
        level: &str,
        code: &str,
        description: &str,
    ) -> Result<(), NetStreamError> {
        // 写入命令名称
        self.amf0_writer.write_string(&String::from("onStatus"))?;
        // 写入事务ID
        self.amf0_writer.write_number(transaction_id)?;
        // 写入空值
        self.amf0_writer.write_null()?;

        // 创建属性映射
        let mut properties_map = IndexMap::new();

        properties_map.insert(
            String::from("level"),
            Amf0ValueType::UTF8String(level.to_owned()),
        );
        properties_map.insert(
            String::from("code"),
            Amf0ValueType::UTF8String(code.to_owned()),
        );
        properties_map.insert(
            String::from("description"),
            Amf0ValueType::UTF8String(description.to_owned()),
        );
        // 写入属性对象
        self.amf0_writer.write_object(&properties_map)?;

        self.write_chunk(1).await
    }
}
